package org.kazuhiko.rpg.server.net.codec;

import java.util.Arrays;

import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolEncoderAdapter;
import org.apache.mina.filter.codec.ProtocolEncoderOutput;
import org.kazuhiko.rpg.server.net.packet.DataType;
import org.kazuhiko.rpg.server.net.packet.Packet;
import org.kazuhiko.rpg.server.net.packet.PacketDefinition;
import org.kazuhiko.rpg.server.net.packet.PacketField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RPGProtocolEncoder extends ProtocolEncoderAdapter
{
	private static final Logger logger = LoggerFactory.getLogger( RPGProtocolEncoder.class );

	@Override
	public void encode( IoSession session, Object message, ProtocolEncoderOutput  out ) throws Exception
	{
		Packet packet = ( Packet ) message;
		PacketDefinition def = packet.getDefinition();
		
		int length = def.getLength() + 1;
		
		for( PacketField field : def.getFields() )
		{
			if( field.getType() == DataType.STRING )
			{
				length += DataType.SHORT.getLength() + packet.getStringField( field.getName() ).length();
			}
		}
		
		IoBuffer buf = IoBuffer.allocate( length );
		buf.put( ( byte ) def.getId() );
		logger.trace( "Sending packet type {} ({})", def.getId(), message );
		
		for( PacketField field : def.getFields() )
		{
			switch( field.getType() )
			{
				case BYTE:
					buf.put( packet.getNumericField( field.getName() ).byteValue() );
					break;
				case SHORT:
					buf.putShort( packet.getNumericField( field.getName() ).shortValue() );
					break;
				case INT:
					buf.putInt( packet.getNumericField( field.getName() ).intValue() );
					break;
				case LONG:
					buf.putLong( packet.getNumericField( field.getName() ).longValue() );
					break;
				case BYTE_ARRAY:
					byte[] data = packet.getByteArrayField( field.getName() );
					byte[] resized = Arrays.copyOf( data, 1024 ); //We only want 1024 bytes
					buf.put( resized );
					break;
				case CLASSIC_STRING:
					String str = packet.getStringField( field.getName() );
					data = str.getBytes();
					resized = Arrays.copyOf( data, 64 ); //We only want 64 bytes
					for( int i = 0; i < resized.length; i++ )
					{
						if( resized[i] == 0 )
						{
							resized[i] = ' ';
						}
					}
					buf.put( resized );
					break;
				case STRING:
					str = packet.getStringField( field.getName() );
					data = str.getBytes();
					buf.putShort( ( short ) str.length() );
					buf.put( data );
					break;
				default:
					//We don't want to handle this packet
					break;
			}
		}
		
		buf.flip();
		out.write( buf ); //send the packet
	}

}
